﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Configuration;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.IO;
using System.Drawing.Imaging;

namespace HomeDmsPageStorageProviders
{
    /// <summary>
    /// Each kind of storage provider must inherit from this interface in order to PageStorage class 
    /// can interact with the particular provider.
    /// </summary>
    public abstract class PageStorageProvider : ProviderBase
    {
        public const string ActiveParamName = "active";
        public const int NameMaxLength = 30;

        private bool _active;

        public bool Active
        {
            get { return _active; }
            set { _active = value; }
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            if (name.Length > NameMaxLength)
                throw new ArgumentException("May not exceed " + NameMaxLength.ToString(), "name");
            if (config == null)
                throw new ArgumentNullException("config");
            if (string.IsNullOrEmpty(config[ActiveParamName]))
                throw new ArgumentNullException(ActiveParamName);
            _active = bool.Parse(config[ActiveParamName]);
            base.Initialize(name, config);
        }

        /// <summary>
        /// Creates new page in storage and returns its unique URI string
        /// </summary>
        /// <param name="name">Some human readable name (e.g. "Page 1") which will be stored together with page 
        /// (e.g. file name in File-based storage provider).
        /// Storage provider may choose to ignore this name and do not store it at all. Though, if it chooses
        /// to store name, it can alter one, but yet, must try to keep it as close to the original as possible.
        /// Store provider never returns this name; after being translated it just stored together with page and may be 
        /// changed with UpdatePage() call.
        /// </param>
        /// <param name="bytes">The page information to store</param>
        /// <returns>Generated unique URI string unambigously identifying this page. After being generated, 
        /// this URI stored together with page and never changed. Example: full file path.
        /// Suggested format: SP://XXX/YYY/ZZZ/....
        /// Here SP - short storage provider name.
        /// </returns>
        public abstract string CreatePage(string name, byte[] bytes);

        /// <summary>
        /// Creates new page in storage and returns its unique URI string
        /// </summary>
        /// <param name="name">Some human readable name (e.g. "Page 1") which will be stored together with page 
        /// (e.g. file name in File-based storage provider).
        /// Storage provider may choose to ignore this name and do not store it at all. Though, if it chooses
        /// to store name, it can alter one, but yet, must try to keep it as close to the original as possible.
        /// Store provider never returns this name; after being translated it just stored together with page and may be 
        /// changed with UpdatePage() call.
        /// </param>
        /// <param name="bytes">The page image to store</param>
        /// <returns>Generated unique URI string unambigously identifying this page. After being generated, 
        /// this URI stored together with page and never changed. Example: full file path.
        /// Suggested format: SP://XXX/YYY/ZZZ/....
        /// Here SP - short storage provider name.
        /// </returns>
        public virtual string CreatePage(string name, Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);
            return CreatePage(name, ms.GetBuffer());
        }

        /// <summary>
        /// Reads saved page from storage
        /// </summary>
        /// <param name="bytes">The unique URI string unambigously identifying this page. This is the very URI that was returned by 
        /// CreatePage() call earlier</param>
        /// <param name="bytes">
        /// The page information
        /// </param>
        public abstract void RetrievePage(string uri, out byte[] bytes);

        /// <summary>
        /// Reads saved page from storage
        /// </summary>
        /// <param name="bytes">The unique URI string unambigously identifying this page. This is the very URI that was returned by 
        /// CreatePage() call earlier</param>
        /// <param name="bytes">
        /// The page image
        /// </param>
        public virtual void RetrievePage(string uri, out Image image)
        {
            byte[] bytes;
            RetrievePage(uri, out bytes);
            MemoryStream ms = new MemoryStream(bytes);
            using (Image image1 = Image.FromStream(ms))
            {
                image = (Image)image1.Clone();
            }
            ms.Close();
        }

        /// <summary>
        /// Updates page in storage
        /// </summary>
        /// <param name="uri">The very URI that was returned by CreatePage() call earlier.
        /// URI string unambigously identifying this page.
        /// </param>
        /// <param name="name">Some human readable name which will be stored together with page 
        /// (e.g. file name in File-based storage provider) and now may have changed so it might need to be updated in storage.
        /// If storage provider stores names, it must update it on this UpdatePage() call.
        /// <seealso cref="CreatePage"/>
        /// </param>
        /// <param name="bytes">The page information to update</param>
        public abstract void UpdatePage(string uri, string name, byte[] bytes);

        /// <summary>
        /// Updates page in storage
        /// </summary>
        /// <param name="uri">The very URI that was returned by CreatePage() call earlier.
        /// URI string unambigously identifying this page.
        /// </param>
        /// <param name="name">Some human readable name which will be stored together with page 
        /// (e.g. file name in File-based storage provider) and now may have changed so it might need to be updated in storage.
        /// If storage provider stores names, it must update it on this UpdatePage() call.
        /// <seealso cref="CreatePage"/>
        /// </param>
        /// <param name="bytes">The page image to update</param>
        public virtual void UpdatePage(string uri, string name, Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);
            UpdatePage(uri, name, ms.GetBuffer());
        }

        /// <summary>
        /// Deletes page from storage
        /// </summary>
        /// <param name="uri">The very URI that was returned by CreatePage() call earlier.
        /// URI string unambigously identifying this page.
        /// </param>
        public abstract void DeletePage(string uri);

        public abstract DialogResult ShowConfigurationDialog(IWin32Window owner);

        public virtual void WriteConfiguration(NameValueCollection nameValueCollection)
        {
            nameValueCollection[ActiveParamName] = _active.ToString();
        }
    }
}
